package NIO;

// DMA -> channel

import org.junit.Test;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Map;
import java.util.Set;

public class TestChannel {

    // 利用通道完成文件的复制（非直接缓冲区）
    @Test
    public void test1() throws IOException {
        FileInputStream fis = null;
        FileOutputStream fos = null;
        // 获取通道
        FileChannel inChannel = null;
        FileChannel outChannel = null;

        try {
            fis = new FileInputStream("src/NIO/1.jpg");
            fos = new FileOutputStream("src/NIO/2.jpg");

            inChannel = fis.getChannel();
            outChannel = fos.getChannel();

            // 分配指定大小缓冲区
            ByteBuffer buf = ByteBuffer.allocate(1024);

            // 将通道数据存入缓冲区
            while (inChannel.read(buf) != -1){
                buf.flip(); // 切换成写模式
                outChannel.write(buf);
                buf.clear();
            }
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            if (fis != null){
                fis.close();
            }
            if (fos != null){
                fos.close();
            }
            if (inChannel != null){
                inChannel.close();
            }
            if (outChannel != null){
                outChannel.close();
            }
        }
    }

    // 利用通道完成文件的复制（直接缓冲区，内存映射文件）
    @Test
    public void test2() throws IOException {
        FileChannel inChannel = FileChannel.open(
                Paths.get("src/NIO/1.jpg"), StandardOpenOption.READ);
        FileChannel outChannel = FileChannel.open(
                Paths.get("src/NIO/3.jpg"), StandardOpenOption.READ,
                StandardOpenOption.WRITE, StandardOpenOption.CREATE);

        // 内存映射文件
        MappedByteBuffer inMappedBuf = inChannel.map(
                FileChannel.MapMode.READ_ONLY, 0, inChannel.size());
        MappedByteBuffer outMappedBuf = outChannel.map(
                FileChannel.MapMode.READ_WRITE, 0, inChannel.size());

        // 直接对缓冲区进行读写操作
        byte[] dst = new byte[inMappedBuf.limit()];
        inMappedBuf.get(dst);
        outMappedBuf.put(dst);
    }

    // 利用通道完成文件的复制（直接缓冲区，利用transferTo）
    @Test
    public void test3() throws IOException {
        FileChannel inChannel = FileChannel.open(
                Paths.get("src/NIO/1.jpg"), StandardOpenOption.READ);
        FileChannel outChannel = FileChannel.open(
                Paths.get("src/NIO/3.jpg"), StandardOpenOption.READ,
                StandardOpenOption.WRITE, StandardOpenOption.CREATE);

        inChannel.transferTo(0, inChannel.size(), outChannel);

        inChannel.close();
        outChannel.close();
    }

    // 分散和聚集
    @Test
    public void test4() throws IOException {
        RandomAccessFile raf1 = new RandomAccessFile("src/NIO/1.txt", "rw");

        FileChannel channel1 = raf1.getChannel();

        // 分配指定大小的缓冲区
        ByteBuffer buf1 = ByteBuffer.allocate(100);
        ByteBuffer buf2 = ByteBuffer.allocate(1024);

        // 分散读取
        ByteBuffer[] bufs = {buf1, buf2};
        channel1.read(bufs);

        for (ByteBuffer buffer : bufs){
            buffer.flip();
        }

        System.out.println(new String(bufs[0].array(), 0, bufs[0].limit()));
        System.out.println("------------------------------------------------");
        System.out.println(new String(bufs[1].array(), 0, bufs[1].limit()));

        // 聚集写入
        RandomAccessFile raf2 = new RandomAccessFile("src/NIO/2.txt", "rw");
        FileChannel channel2 = raf2.getChannel();

        channel2.write(bufs);
    }

    // 字符集（charset）编码和解码
    @Test
    public void test5(){
        Map<String, Charset> map = Charset.availableCharsets();

        Set<Map.Entry<String, Charset>> set = map.entrySet();

        for (Map.Entry<String, Charset> entry : set){
            System.out.println(entry.getKey() + " = " + entry.getValue());
        }
    }

    // 字符集（charset）编码和解码
    @Test
    public void test6() throws CharacterCodingException {
        Charset cs1 = Charset.forName("GBK");

        // 获取编码器
        CharsetEncoder ce = cs1.newEncoder();

        // 获取解码器
        CharsetDecoder cd = cs1.newDecoder();

        CharBuffer cBuf = CharBuffer.allocate(1024);
        cBuf.put("尚硅谷威武！");
        cBuf.flip();
        // 编码
        ByteBuffer bBuf = ce.encode(cBuf);

        for (int i = 0; i < 12; i++) {
            System.out.println(bBuf.get());
        }

        System.out.println("------------------------");
        // 解码
        bBuf.flip();
        CharBuffer cb2 = cd.decode(bBuf);
        System.out.println(cb2.toString());
    }
}
